package com.yangda.example.framework.exception;

import com.yangda.example.framework.ResultCode;
import com.yangda.example.framework.model.Response;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.http.server.ServletServerHttpResponse;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 * 
 * @文件名 :AnnotationHandlerMethodExceptionResolver.java
 * @创建人 :carl
 * @时间 :2016年7月29日 上午9:39:39
 * @描述 :统一异常处理
 */
public class AnnotationHandlerMethodExceptionResolver extends ExceptionHandlerExceptionResolver {
	protected Logger logger = LoggerFactory.getLogger(getClass());

	 private String defaultErrorView;  
	  
	    public String getDefaultErrorView() {  
	        return defaultErrorView;  
	    }  
	  
	    public void setDefaultErrorView(String defaultErrorView) {  
	        this.defaultErrorView = defaultErrorView;  
	    }  
	  
	    protected ModelAndView doResolveHandlerMethodException(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod, Exception exception) {  
	    	logger.error("错误异常:{}", exception.getMessage());
	    	logger.error("错误信息:{}", exception.getLocalizedMessage());
	    	
	        if (handlerMethod == null) {  
	            return null;  
	        }  
	  
	        Method method = handlerMethod.getMethod();  
	  
	        if (method == null) {  
	            return null;  
	        }  
	        //如果定义了ExceptionHandler则返回相应的Map中的数据  
	        ModelAndView returnValue = super.doResolveHandlerMethodException(request, response, handlerMethod, exception);  
	        ResponseBody responseBodyAnn = AnnotationUtils.findAnnotation(method, ResponseBody.class);  
	        if (responseBodyAnn != null) {  
	            try {  
	                ResponseStatus responseStatusAnn = AnnotationUtils.findAnnotation(method, ResponseStatus.class);  
	                if (responseStatusAnn != null) {  
	                    HttpStatus responseStatus = responseStatusAnn.value();  
	                    String reason = responseStatusAnn.reason();  
	                    if (!StringUtils.hasText(reason)) {  
	                        response.setStatus(responseStatus.value());  
	                    } else {  
	                        try {  
	                            response.sendError(responseStatus.value(), reason);  
	                        } catch (IOException e) { }  
	                    }  
	                }  
	                // 如果没有ExceptionHandler注解那么returnValue就为空  
	                if (returnValue == null) {  
	                	
	                	BizException bizException = null;
	                	
	                	Response resultModel = new Response();
	                	if(exception instanceof BizException){
							//自定义的业务异常
	                		bizException = (BizException)exception;
	                		resultModel.setCode(bizException.getErrorCode());
		                	resultModel.setMsg(bizException.getMessage());
	                	}else{
							resultModel.setCode(ResultCode.SYSTEM_ERROR.getCode());
							resultModel.setMsg(ResultCode.SYSTEM_ERROR.getMessage());
	                	}
	                	
	                    handleResponseError(resultModel, request, response);  
	                    
	                    return new ModelAndView();  
	                }  
	                return handleResponseBody(returnValue, request, response);  
	            } catch (Exception e) {  
	            	logger.error("错误异常:{}", e.getMessage());
	                return null;  
	            }  
	        }  
	  
	        if( null == returnValue) {  
	            returnValue = new ModelAndView();  
	            if (null == returnValue.getViewName()) {  
	                returnValue.setViewName(defaultErrorView);  
	            }  
	        }  
	        return returnValue;  
	    }  
	  
	  
	    @SuppressWarnings({ "unchecked", "rawtypes" })  
	    private ModelAndView handleResponseBody(ModelAndView returnValue, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {  
	        Map value = returnValue.getModelMap();  
	        HttpInputMessage inputMessage = new ServletServerHttpRequest(request);  
	        List<MediaType> acceptedMediaTypes = inputMessage.getHeaders().getAccept();  
	        if (acceptedMediaTypes.isEmpty()) {  
	            acceptedMediaTypes = Collections.singletonList(MediaType.ALL);  
	        }  
	        MediaType.sortByQualityValue(acceptedMediaTypes);  
	        HttpOutputMessage outputMessage = new ServletServerHttpResponse(response);  
	        Class<?> returnValueType = value.getClass();  
	        List<HttpMessageConverter<?>> messageConverters = super.getMessageConverters();  
	        if (messageConverters != null) {  
	            for (MediaType acceptedMediaType : acceptedMediaTypes) {  
	                for (HttpMessageConverter messageConverter : messageConverters) {  
	                    if (messageConverter.canWrite(returnValueType, acceptedMediaType)) {  
	                        messageConverter.write(value, acceptedMediaType, outputMessage);  
	                        return new ModelAndView();  
	                    }  
	                }  
	            }  
	        }  
	        if (logger.isWarnEnabled()) {  
	            logger.warn("Could not find HttpMessageConverter that supports return type [" + returnValueType + "] and " + acceptedMediaTypes);  
	        }  
	        return null;  
	    }  
	    @SuppressWarnings({ "unchecked", "rawtypes" })  
	    private ModelAndView handleResponseError(Response returnValue, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	        HttpInputMessage inputMessage = new ServletServerHttpRequest(request);  
	        List<MediaType> acceptedMediaTypes = inputMessage.getHeaders().getAccept();  
	        if (acceptedMediaTypes.isEmpty()) {  
	            acceptedMediaTypes = Collections.singletonList(MediaType.ALL);  
	        }  
	        MediaType.sortByQualityValue(acceptedMediaTypes);  
	        HttpOutputMessage outputMessage = new ServletServerHttpResponse(response);  
	        Class<?> returnValueType = returnValue.getClass();  
	        List<HttpMessageConverter<?>> messageConverters = super.getMessageConverters();  
	        if (messageConverters != null) {  
	            for (MediaType acceptedMediaType : acceptedMediaTypes) {  
	                for (HttpMessageConverter messageConverter : messageConverters) {  
	                    if (messageConverter.canWrite(returnValueType, acceptedMediaType)) {  
	                        messageConverter.write(returnValue, acceptedMediaType, outputMessage);  
	                        return new ModelAndView();  
	                    }  
	                }  
	            }  
	        }  
	        if (logger.isWarnEnabled()) {  
	            logger.warn("Could not find HttpMessageConverter that supports return type [" + returnValueType + "] and " + acceptedMediaTypes);  
	        }  
	        return null;  
	    }  
}
